"""
展示如何使用Doctest进行测试
"""


def factorial(n):
    """
    Return the factorial of n, an exact integer >= 0.

    >>> [factorial(x) for x in range(6)]
    [1, 1, 2, 6, 24, 120]
    >>> factorial(5)
    120
    >>> factorial(-1)
    Traceback (most recent call last):
        ...
    ValueError: n must be >= 0
    """

    import math
    if not n >= 0:
        raise ValueError("n must be >= 0")
    if math.floor(n) != n:
        raise ValueError("n must be exact integer")
    if n+1 == n:  # catch a value like 1e300
        raise OverflowError("n too large")
    result = 1
    factor = 2
    while factor <= n:
        result *= factor
        factor += 1
    return result


class ListCounter:
    """
    count the number of some element in a list or tuple

    >>> counter = ListCounter(3)
    >>> counter.count_element([2, 3, 3])
    2
    >>> counter.count_not_element([2, 3, 3])
    1
    """

    def __init__(self, element):
        self.element = element

    def count_element(self, list_):
        """
        count element that in list_

        >>> ListCounter(2).count_element([1, 2, 2, 2])
        3
        """
        return sum([1 for x in list_ if x == self.element])

    def count_not_element(self, list_):
        """
        count the number of all elements that are in the list and not the assigned element
        :param list_:
        :return:
        """
        return sum([1 for x in list_ if x != self.element])

    def count_empty_error(self, list_):
        """
        raise ValueError if input a empty list

        >>> ListCounter(3).count_empty_error([])
        Traceback (most recent call last):
           ...
        ValueError: no element in list_
        """

        if not list_:
            raise ValueError("no element in list_")
        return self.count_element(list_)


if __name__ == '__main__':
    import doctest
    doctest.testmod()
